// Created by Windward Studios - no copyright is claimed. This code can be used in
// any manner by anyone for any reason. There is no copyright of any kind on it. You may
// use it in commercial products. You may change it without sharing those changes.
// We ask that you keep the "created by Windward Studios" in a comment at the top.

using System.Data;
using System.Data.Common;
using Kailua.net.windward.utils;
using net.windward.utils.ado.DB2;
using net.windward.utils.ado.Excel;
using net.windward.utils.ado.MySql;
using net.windward.utils.ado.ODBC;
using net.windward.utils.ado.OleDb;
using net.windward.utils.ado.Oracle;
using net.windward.utils.ado.SPList;
using net.windward.utils.ado.SqlServer;
using net.windward.utils.ado.Unknown;

namespace net.windward.utils.ado
{
	/// <summary>
	/// Wraps a DbCommand object and provides a client independent method of setting parameters. All parameters are
	/// set as ? in the sql commands are are set based on their order. This also has an ExecuteInsert that if given
	/// a sql command to insert a single row, will return the value of the auto primary key for that row.
	/// </summary>
	public abstract class WrCommand : IDbCommand
	{

		/// <summary>
		/// The underlying IDbCommand object.
		/// </summary>
		protected IDbCommand cmd;

		/// <summary>
		/// Create a DbCommand wrapper.
		/// </summary>
		/// <param name="provider">The DB provider to use.</param>
		/// <param name="connection">The connection to use.</param>
		public static WrCommand Factory(DbProviderFactory provider, IDbConnection connection)
		{
			WrCommand cmd = Factory(provider, WrConnection.GetOdbcProvider(provider.GetType().FullName, connection.ConnectionString));
			cmd.Connection = connection;
			return cmd;
		}

		/// <summary>
		/// Create a DbCommand wrapper.
		/// </summary>
		/// <param name="provider">The DB provider to use.</param>
		/// <param name="odbcProvider">The ODBC provider to use.</param>
		public static WrCommand Factory(DbProviderFactory provider, string odbcProvider)
		{
			switch (WrProviderFactories.DetermineProvider(provider.GetType().FullName))
			{
				case "DB2":
					return new WrDB2Command(provider);
				case "MySql":
					return new WrMySqlCommand(provider);
				case "ODBC":
					return new WrOdbcCommand(provider, odbcProvider);
				case "OleDb":
                    if ((odbcProvider.ToLower() == "microsoft.ace.oledb.12.0 (*.xlsx, *.xlsb, *.xlsm)") || (odbcProvider.ToLower() == "microsoft.jet.oledb.4.0 (*.xls, *.csv)"))
                        return new WrExcelCommand(provider, odbcProvider);
                    if (odbcProvider.ToLower().Equals("microsoft.ace.oledb.12.0 (sharepoint list)"))
                        return new WrSPListCommand(provider, odbcProvider);
                    return new WrOleDbCommand(provider, odbcProvider);
				case "Oracle":
					return new WrOracleCommand(provider);
				case "SqlServer":
					return new WrSqlServerCommand(provider);
			}

			Trap.trap();
			return new WrUnknownCommand(provider);
		}

		/// <summary>
		/// Set the value of a parameter.
		/// </summary>
		/// <param name="ind">The index of this paramater in the command.</param>
		/// <param name="value">The value of this parameter.</param>
		public abstract void Set(int ind, object value);

		///<summary>
		///Used for inserting a row with an auto primary key. Executes an SQL statement against the Connection object of a .NET Framework 
		/// data provider, and returns the value of the primary key.
		///</summary>
		/// <param name="pkName">The name of the PK column</param>
		///<returns>
		///The value of the primary key for the inserted row.
		///</returns>
		///<exception cref="T:System.InvalidOperationException">The connection does not exist.-or- The connection is not open. </exception><filterpriority>2</filterpriority>
		public abstract long ExecuteInsert(string pkName);


		#region IDisposable Members

		///<summary>
		///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		///</summary>
		///<filterpriority>2</filterpriority>
		public virtual void Dispose()
		{
			cmd.Dispose();
		}

		#endregion

		#region IDbCommand Members

		///<summary>
		///Creates a prepared (or compiled) version of the command on the data source.
		///</summary>
		///
		///<exception cref="T:System.InvalidOperationException">The <see cref="P:System.Data.OleDb.OleDbCommand.Connection"></see> 
		/// is not set.-or- The <see cref="P:System.Data.OleDb.OleDbCommand.Connection"></see> is not OleDbConnection.Open. </exception>
		/// <filterpriority>2</filterpriority>
		public virtual void Prepare()
		{
			cmd.Prepare();
		}

		///<summary>
		///Attempts to cancels the execution of an <see cref="T:System.Data.IDbCommand"></see>.
		///</summary>
		///<filterpriority>2</filterpriority>
		public virtual void Cancel()
		{
			cmd.Cancel();
		}

		///<summary>
		///Creates a new instance of an <see cref="T:System.Data.IDbDataParameter"></see> object.
		///</summary>
		///
		///<returns>
		///An IDbDataParameter object.
		///</returns>
		///<filterpriority>2</filterpriority>
		public virtual IDbDataParameter CreateParameter()
		{
			return cmd.CreateParameter();
		}

		///<summary>
		///Executes an SQL statement against the Connection object of a .NET Framework data provider, and returns the number of rows affected.
		///</summary>
		///
		///<returns>
		///The number of rows affected.
		///</returns>
		///
		///<exception cref="T:System.InvalidOperationException">The connection does not exist.-or- The connection is not open. </exception><filterpriority>2</filterpriority>
		public virtual int ExecuteNonQuery()
		{
			return cmd.ExecuteNonQuery();
		}

		///<summary>
		///Executes the <see cref="P:System.Data.IDbCommand.CommandText"></see> against the 
		/// <see cref="P:System.Data.IDbCommand.Connection"></see> and builds an <see cref="T:System.Data.IDataReader"></see>.
		///</summary>
		///
		///<returns>
		///An <see cref="T:System.Data.IDataReader"></see> object.
		///</returns>
		///<filterpriority>2</filterpriority>
		public abstract IDataReader ExecuteReader();

		///<summary>
		///Executes the <see cref="P:System.Data.IDbCommand.CommandText"></see> against the 
		/// <see cref="P:System.Data.IDbCommand.Connection"></see> and builds an <see cref="T:System.Data.IDataReader"></see>.
		///</summary>
		///
		///<returns>
		///An <see cref="T:System.Data.IDataReader"></see> object.
		///</returns>
		///<filterpriority>2</filterpriority>
		public virtual WrDataReader WrExecuteReader()
		{
			return (WrDataReader)ExecuteReader();
		}

		///<summary>
		///Executes the <see cref="P:System.Data.IDbCommand.CommandText"></see> against the 
		/// <see cref="P:System.Data.IDbCommand.Connection"></see>, and builds an <see cref="T:System.Data.IDataReader"></see> 
		/// using one of the <see cref="T:System.Data.CommandBehavior"></see> values.
		///</summary>
		///
		///<returns>
		///An <see cref="T:System.Data.IDataReader"></see> object.
		///</returns>
		///
		///<param name="behavior">One of the <see cref="T:System.Data.CommandBehavior"></see> values. </param>
		/// <filterpriority>2</filterpriority>
		public abstract IDataReader ExecuteReader(CommandBehavior behavior);

		///<summary>
		///Executes the query, and returns the first column of the first row in the resultset returned by the query. Extra columns or rows are ignored.
		///</summary>
		///
		///<returns>
		///The first column of the first row in the resultset.
		///</returns>
		///<filterpriority>2</filterpriority>
		public virtual object ExecuteScalar()
		{
			return cmd.ExecuteScalar();
		}

		///<summary>
		///Gets or sets the <see cref="T:System.Data.IDbConnection"></see> used by this instance of the <see cref="T:System.Data.IDbCommand"></see>.
		///</summary>
		///
		///<returns>
		///The connection to the data source.
		///</returns>
		///<filterpriority>2</filterpriority>
		public virtual IDbConnection Connection
		{
			get { return cmd.Connection; }
			set { cmd.Connection = value; }
		}

		///<summary>
		///Gets or sets the transaction within which the Command object of a .NET Framework data provider executes.
		///</summary>
		///
		///<returns>
		///the Command object of a .NET Framework data provider executes. The default value is null.
		///</returns>
		///<filterpriority>2</filterpriority>
		public virtual IDbTransaction Transaction
		{
			get { return cmd.Transaction; }
			set { cmd.Transaction = value; }
		}

		///<summary>
		///Gets or sets the text command to run against the data source.
		///</summary>
		///
		///<returns>
		///The text command to execute. The default value is an empty string ("").
		///</returns>
		///<filterpriority>2</filterpriority>
		public abstract string CommandText
		{
			get;
			set;
		}

		///<summary>
		///Gets or sets the wait time before terminating the attempt to execute a command and generating an error.
		///</summary>
		///
		///<returns>
		///The time (in seconds) to wait for the command to execute. The default value is 30 seconds.
		///</returns>
		///
		///<exception cref="T:System.ArgumentException">The property value assigned is less than 0. </exception><filterpriority>2</filterpriority>
		public virtual int CommandTimeout
		{
			get { return cmd.CommandTimeout; }
			set { cmd.CommandTimeout = value; }
		}

		///<summary>
		///Indicates or specifies how the <see cref="P:System.Data.IDbCommand.CommandText"></see> property is interpreted.
		///</summary>
		///
		///<returns>
		///One of the <see cref="T:System.Data.CommandType"></see> values. The default is Text.
		///</returns>
		///<filterpriority>2</filterpriority>
		public virtual CommandType CommandType
		{
			get { return cmd.CommandType; }
			set { cmd.CommandType = value; }
		}

		///<summary>
		///Gets the <see cref="T:System.Data.IDataParameterCollection"></see>.
		///</summary>
		///
		///<returns>
		///The parameters of the SQL statement or stored procedure.
		///</returns>
		///<filterpriority>2</filterpriority>
		public virtual IDataParameterCollection Parameters
		{
			get { return cmd.Parameters; }
		}

		///<summary>
		///Gets or sets how command results are applied to the <see cref="T:System.Data.DataRow"></see> when used by the <see cref="M:System.Data.IDataAdapter.Update(System.Data.DataSet)"></see> method of a <see cref="T:System.Data.Common.DbDataAdapter"></see>.
		///</summary>
		///
		///<returns>
		///One of the <see cref="T:System.Data.UpdateRowSource"></see> values. The default is Both unless the command is automatically generated. Then the default is None.
		///</returns>
		///
		///<exception cref="T:System.ArgumentException">The value entered was not one of the <see cref="T:System.Data.UpdateRowSource"></see> values. </exception><filterpriority>2</filterpriority>
		public virtual UpdateRowSource UpdatedRowSource
		{
			get { return cmd.UpdatedRowSource; }
			set { cmd.UpdatedRowSource = value; }
		}

		#endregion

	}
}
